package pl.pelcra.cesar.spider.runner;

import java.util.Map;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.PosixParser;
import org.apache.log4j.Logger;

import pl.pelcra.cesar.data.interfaces.ICommonData;
import pl.pelcra.cesar.database.configuration.DBConfiguration;
import pl.pelcra.cesar.database.pool.DBConfigurationPooler;
import pl.pelcra.cesar.database.pool.DBConnectionPooler;
import pl.pelcra.cesar.spider.data.AttachmentThreadData;
import pl.pelcra.cesar.spider.data.MapLangUrl;
import pl.pelcra.cesar.spider.data.SpiderThreadDataNew;
import pl.pelcra.cesar.spider.datadownloader.DataDownloader;
import pl.pelcra.cesar.spider.utils.CesarSpiderAppConfiguration;
import pl.pelcra.cesar.spider.webcrawler.CrawlController;
import pl.pelcra.cesar.spider.webcrawler.PageFetcher;
import pl.pelcra.cesar.spider.webcrawler.WebCrawler;
import pl.pelcra.cesar.spider.webcrawler.interfaces.BasePageWebTasks;
import pl.pelcra.cesar.spider.webparser.WebParser;
import pl.pelcra.cesar.tools.Tools;
import pl.pelcra.cesar.webrecorder.database.tables.DBLog;
import pl.pelcra.cesar.webrecorder.database.tables.DBWeb_Record;
import pl.pelcra.cesar.webrecorder.database.tables.DBWeb_RecordDAO;
import pl.pelcra.cesar.webrecorder.provision.LogWebRecordThreadDataNew;
import pl.pelcra.cesar.webrecorder.provision.LogWebRecorderProvisioning;
import pl.pelcra.cesar.webrecorder.provision.WebRecordThreadDataNew;
import pl.pelcra.cesar.webrecorder.provision.WebRecorderProvisioning;
import edu.uci.ics.crawler4j.crawler.CrawlConfig;

/**
 * main class which run spider
 * 
 * @author margielewski
 * 
 */
public class StartUp {

	private static String appConfigFileName = new String("appConfig.xml");
	private static Logger logger = Logger.getLogger(StartUp.class);
	private static String pelcraConfigFileName = new String("dbConfig.xml");

	/**
	 * @param args
	 *            - arguments to start main class
	 */
	public static void main(String[] args) {
		if (manageAppArguments(args)) {
			logger.info("WikiWebSpider start up");

			DBConfigurationPooler.INSTANCE
					.setCpWebRecordConfiguration(new DBConfiguration(
							pelcraConfigFileName));

			CesarSpiderAppConfiguration appConfig = new CesarSpiderAppConfiguration(
					appConfigFileName);

			// if (test())
			// return;

			try {
				LogWebRecorderProvisioning threadLogWebRecordProvisioning = null;
				WebRecorderProvisioning threadWebRecordProvisioning = null;

				if (appConfig.isRunSpider()) {
					CrawlConfig crawlConfig = new CrawlConfig();
					crawlConfig.setCrawlStorageFolder(appConfig
							.getCrawlStorageFolder());
					crawlConfig.setPolitenessDelay(appConfig
							.getPolitenessDelay());
					crawlConfig.setUserAgentString(appConfig
							.getUserAgentString());
					crawlConfig.setSocketTimeout(appConfig.getSocketTimeout());
					crawlConfig.setConnectionTimeout(appConfig
							.getConnectionTimeout());
					crawlConfig.setProxyHost(appConfig.getProxyHost());
					crawlConfig.setProxyUsername(appConfig.getProxyUsername());
					crawlConfig.setProxyPassword(appConfig.getProxyPassword());
					crawlConfig.setProxyPort(appConfig.getProxyPort());

					PageFetcher pageFetcher = new PageFetcher(crawlConfig);

					CrawlController controller = new CrawlController(
							crawlConfig, pageFetcher);

					ICommonData<MapLangUrl> spiderThreadData = new SpiderThreadDataNew();

					// MapLangUrl url = new MapLangUrl();
					// url.put("pl",
					// new CSWebURL(
					// controller
					// .getSeed("http://www.osw.waw.pl/pl/publikacje/prace-osw/2008-09-15/trudny-sojusznik-bialorus-w-polityce-rosji")));
					// spiderThreadData.put(url);

					BasePageWebTasks pageCrawled = Tools.loadClass(
							BasePageWebTasks.class,
							appConfig.getWebTasksClassName(),
							new Object[] { appConfig.getWebTasksParameters() });

					pageCrawled.init(
							controller.getSeed(appConfig.getStartSiteUrl()),
							spiderThreadData);

					controller.setWebCrawler(WebCrawler.class);
					controller.setWebTask(pageCrawled.getMainWebTask());
					controller.setThreadData(spiderThreadData);

					Thread threadSpider = new Thread(controller);
					threadSpider.start();

					Tools.threadSleep(2000);

					ICommonData<DBLog> logWebRecordThreadData = new LogWebRecordThreadDataNew();

					ICommonData<DBWeb_Record> webRecordThreadData = new WebRecordThreadDataNew();
					WebParser webParser = new WebParser(spiderThreadData,
							webRecordThreadData, logWebRecordThreadData,
							appConfig.getParserClassName(),
							appConfig.getParserParameters(),
							appConfig.getPolitenessDelay());
					webParser.start();

					Tools.threadSleep(2000);

					threadWebRecordProvisioning = new WebRecorderProvisioning(
							webRecordThreadData);
					threadWebRecordProvisioning.start();

					Tools.threadSleep(2000);

					threadLogWebRecordProvisioning = new LogWebRecorderProvisioning(
							logWebRecordThreadData);
					threadLogWebRecordProvisioning.start();
				}

				if (appConfig.isRunAttachmentDownloader()) {
					if (appConfig.isRunSpider()) {

						if (threadLogWebRecordProvisioning != null) {
							threadLogWebRecordProvisioning.join();
						}

						if (threadWebRecordProvisioning != null) {
							threadWebRecordProvisioning.join();
						}
					}

					DBWeb_RecordDAO web_RecordDAO = new DBWeb_RecordDAO(
							DBConnectionPooler.INSTANCE
									.getCPWebRecordConnection());

					ICommonData<Map.Entry<Integer, String>> attachmentThreadData = new AttachmentThreadData();
					((AttachmentThreadData) attachmentThreadData)
							.putAll(web_RecordDAO.GetAttachmentDBWeb_Record());
					attachmentThreadData.endPutting();

					DataDownloader dataDownloaderThread = new DataDownloader(
							attachmentThreadData);
					dataDownloaderThread.start();
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	@SuppressWarnings("static-access")
	private static Boolean manageAppArguments(String[] args) {

		Options options = new Options();

		Option optionHelp = new Option("h", "help", false, "Display help");

		Option optionPelcraConfigFile = OptionBuilder
				.withArgName("file")
				.hasOptionalArg()
				.withDescription(
						"use given file for reading configuration for database")
				.withLongOpt("dbCONFIG").create("dbc");

		Option optionConfigApp = OptionBuilder
				.withArgName("option")
				.hasOptionalArg()
				.withDescription(
						"use given file for reading configuration for app")
				.withLongOpt("appConfig").create("appc");

		options.addOption(optionHelp);
		options.addOption(optionPelcraConfigFile);
		options.addOption(optionConfigApp);

		CommandLineParser parser = new PosixParser();
		try {
			CommandLine cmd = parser.parse(options, args);

			if (cmd.hasOption(optionHelp.getOpt())) {
				HelpFormatter helpFormatter = new HelpFormatter();
				helpFormatter.printHelp("WikiDict", options);
				return false;
			} else {
				if (cmd.hasOption(optionConfigApp.getOpt())) {
					appConfigFileName = cmd.getOptionValue("appc");
					logger.info("App is run with config " + appConfigFileName);
				} else {
					logger.info("Read configuration for App from default file: "
							+ appConfigFileName);
				}

				if (cmd.hasOption(optionPelcraConfigFile.getOpt())) {
					pelcraConfigFileName = cmd.getOptionValue("dbc");
				} else {
					logger.info("Read configuration for Pelcra from default file: "
							+ pelcraConfigFileName);
				}
			}
		} catch (ParseException ex) {
			logger.error(ex.getMessage());
			return false;
		}
		return true;
	}
}